import java.util.HashSet;
import java.util.Set;

public class Leetcode36 {

    private static final char BLANK = '.';

    private static final int[][] BLOCK_START_INDEX = {
            {0, 0}, {0, 3}, {0, 6},
            {3, 0}, {3, 3}, {3, 6},
            {6, 0}, {6, 3}, {6, 6},
    };

    private static final int BLOCK_LENGTH = 3;

    public static boolean isValidSudoku(char[][] board) {
        return checkBlock(board) && checkColumn(board) && checkRow(board);
    }

    private static boolean checkRow(char[][] board) {
        for (char[] chars : board) {
            Set<Character> set = new HashSet<>();
            for (char c : chars) {
                if (c == BLANK) {
                    continue;
                }
                if (set.contains(c)) {
                    return false;
                }

                set.add(c);
            }
        }

        return true;
    }

    private static boolean checkColumn(char[][] board) {
        int n = board[0].length;
        for (int column = 0; column < n; column++) {
            Set<Character> set = new HashSet<>();
            for (char[] row : board) {
                if (row[column] == BLANK) {
                    continue;
                }
                if (set.contains(row[column])) {
                    return false;
                }

                set.add(row[column]);
            }
        }

        return true;
    }

    private static boolean checkBlock(char[][] board) {
        for (int[] blockStartIndex : BLOCK_START_INDEX) {
            Set<Character> set = new HashSet<>();

            for (int row = 0; row < BLOCK_LENGTH; row++) {
                for (int column = 0; column < BLOCK_LENGTH; column++) {
                    if (board[blockStartIndex[0] + row][blockStartIndex[1] + column] == BLANK) {
                        continue;
                    }
                    if (set.contains(board[blockStartIndex[0] + row][blockStartIndex[1] + column])) {
                        return false;
                    }

                    set.add(board[blockStartIndex[0] + row][blockStartIndex[1] + column]);
                }
            }
        }

        return true;
    }
}
